/**
 * @author Austin Andrews (Templarian)
 * @authorurl http://templarian.com
 * @framework DD Framework
 * @licence New BSD License
 * @licenceurl http://ddframework.googlecode.com/svn/trunk/license.txt
 * @overview DD Micro Framework
 */
/**
 * Use as a function or to access properties
 * @namespace dd
 * @property
 *  Access modules and core functionality
 * @function
 *  Select a dom element by id attribute
 *  @param id {string} An id attribute of a visible dom element
 *  @returns dd.fn
 * @function
 *  Select a dom element by passing an object
 *  @param dom {object} Dom elment
 *  @returns dd.fn
*/
var dd = function(o1, o2)
{
    return dd.is(o2)
        ? function()
        {
            dd.combine(this, o2);
            o1.apply(this, arguments);
        }
        : dd.is(o1, "string")
            ? dd.fn.init.call(dd, o1)
            : dd.fn.init.call(dd, o1);
};
/**
 * is
 * @namespace dd.is
 * @function
 *  Check if variable is Undefined
 *  @param value {} Value to check
 *  @param type {string} Type to check against
 *  @returns element
 * @function
 *  Check if key is in object
 *  @param key {} Key
 *  @param object {string} Object
 *  @returns element
 */
dd.is = function(v, t)
{
    var _v = v instanceof Array ? "array" : typeof(v);
    var _t = t instanceof Array ? "array" : typeof(t);
    if(_t === "undefined")
    {
        return v === null ? false : _v !== "undefined";
    }
    else if(_t === "string")
    {
        return _v === t;
    }
    else if(_t === "array")
    {
        if(this._a !== t)
        {
            this._o = {};
            for(var i = 0; i < t.length; i++)
            {
                this._o[t[i]] = null;
            }
            this._a = t;
        }
        return v in this._o;
    }
    else if(_v === "array")
    {
        for(var i = 0; i < v.length; i++)
        {
            if(v[i] in t)
            {
                return true;
            }
        }
        return false;
    }
    else if(_t == "object")
    {
        return typeof(t[v]) !== "undefined";
    }
    alert("Error: dd.is");
    return false;
};
dd.extend = function(o1)
{
    for(var i in o1)
    {
        dd[i] = o1[i];
    }
};
dd.extend({
    head:document.getElementsByTagName("head")[0],
    body:document.getElementsByTagName("body")[0],
    fn:{
        init:function(o)
        {
            o = o instanceof Array ? o : [o];
            var r = [];
            for(var i = 0; i < o.length; i++)
            {
                var m = typeof(o[i]) == "string"
                    ? {e:document.getElementById(o[i])}
                    : "self" in o[i]
                        ? o[i].self
                        : "attributes" in o[i]
                            ? {e:o[i]}
                            : o[i];
                m.e = "e" in m
                        ? m.e
                        : null;
                m.fn = "fn" in m ? m.fn : dd.fn;
                m.nodeName = m.e !== null ? m.e.nodeName.toLowerCase() : null;
                r.push(m.fn.self = m);
            }
            if(r.length > 1)
            {
                var t = {};
                for(var i in r)
                {
                    for(var j in dd._fn)
                    {
                        t[dd._fn[j]] = dd.fnF(r, dd._fn[j], t);
                    }
                }
                return t;
            }
            else
            {
                return r[0].fn;
            }
        },
        /**
         * Initiates 
         * @namespace dd.fn.addElement
         * @function
         *  Add element to DOM
         *  @param name {string} Element name
         *  @returns {object} element
         * @function
         *  Add element to DOM
         *  @param name {string} Element name
         *  @param innerText {string} Inner text
         *  @returns element
         *  @function
         *  Add element to DOM
         *  @param name {string} Element name
         *  @param innerText {object} Attributes
         *  @returns {object} element
         * @function
         *  Add element to DOM
         *  @param name {string} Element name
         *  @param innerText {string} Inner text
         *  @param attributes {object} Attributes
         *  @returns {object} element
         * @function
         *  Add element to DOM
         *  @param namespace_name {object} Dom elment, ex: {"svg":"rect"}
         *  @returns {object} element
         * @function
         *  Add element to DOM
         *  @param namespace_name {object} Dom elment, ex: {"svg":"rect"}
         *  @param attribute {object} Attributes
         *  @returns {object} element
         * @function
         *  Add element to DOM
         *  @param namespace_name {object} Element name, ex: {"svg":"rect"}
         *  @param innerText {string} Inner text
         *  @param id {object} Attributes
         *  @returns {object} element
         */
        addElement:function(o1, o2, o3, o4)
        {
            var e = {};
            if(dd.is(o1, "string"))
            {
                e = document.createElement(o1);
            }
            else if(dd.is(o1, "object"))
            {
                for(var i in o1)
                {
                    e = document.createElementNS(dd._ns[i], i + ":" + o1[i]);
                }
            }
            if(dd.is(o2, "object"))
            {
                for(var j in o2)
                {
                    e.setAttribute(j, o2[j]);
                }
            }
            else if(dd.is(o2, "string") || dd.is(o2, "number"))
            {
                if(o2 != "")
                {
                    e.appendChild(document.createTextNode(o2));
                }
            }
            if(o3)
            {
                for(var k in o3)
                {
                    e.setAttribute(k, o3[k]);
                }
            }
            if(dd.is(o1, "boolean") || dd.is(o2, "boolean")
               || dd.is(o3, "boolean") || dd.is(o4, "boolean"))
            {
                this.self.e.insertBefore(e, this.self.e.firstChild);
            }
            else
            {
                this.self.e.appendChild(e);
            }
            return {e:e, event:{}};
        },
        /**
         * Removes selector
         * @namespace dd.fn.remove
         * @function
         *  Removes element from DOM
         */
        remove:function()
        {
            var e = this.self.e;
            e.parentNode.removeChild(e);
        },
        /**
         * Removes contents of selector
         * @namespace dd.fn.empty
         * @function
         *  Clears inner DOM elements
         */
        empty:function()
        {
            var e = this.self.e;
            while(e.childNodes[0])
            {
                e.removeChild(e.childNodes[0]);
            }
        },
        className:function(v)
        {
            if(v)
            {
                var e = this.self.e;
                if(typeof(e.className) == "object")
                {
                    return e.className.baseVal = v;
                }
                else
                {
                    return e.className = v;
                }
            }
            else
            {
                var e = this.self.e;
                return typeof(e.className) == "object"
                    ? e.className.baseVal
                    : e.className;
            }
        },
        /**
         * Add's a CSS class to an element 
         * @namespace dd.fn.addClass
         * @function
         *  Add element to DOM
         *  @param name {string} Element name
         *  @returns element
         */
        addClass:function(name)
        {
            var c = dd(this).className().split(/ /);
            c.push(name);
            dd(this).className(dd.trim(c.join(" ")));
            return this;
        },
        /**
         * Removes a CSS class from an element 
         * @namespace dd.fn.removeClass
         * @function
         *  Add element to DOM
         *  @param name {string} Element name
         *  @returns element
         */
        removeClass:function(name)
        {
            dd(this).className(dd.trim((dd(this).className + " ")
                                                  .replace(new RegExp(name + " ", "g"), "")));
            return this;
        },
        /**
         * Clears CSS classes on element 
         * @namespace dd.fn.clearClass
         * @function
         *  Add element to DOM
         *  @param name {string} Element name
         *  @returns element
         */
        clearClass:function()
        {
            dd(this).className("");
            return this;
        },
        /**
         * Checks if class exists
         * @namespace dd.fn.classExists
         * @function
         *  Add element to DOM
         *  @param name {string} Class name
         *  @returns boolean
         */
        hasClass:function(name)
        {
            return !!~(" " + dd(this).className() + " ").indexOf(" " + name + " ");
        },
        /**
         * Set an element's attribute 
         * @namespace dd.fn.setAttribute
         * @function
         *  Add element to DOM
         *  @param name {string} Attribute name
         *  @param value {string} Attribute value
         */
        setAttribute:function(name, value)
        {
            this.self.e.setAttribute(name, value);
        },
        /**
         * Get an element's attribute 
         * @namespace dd.fn.getAttribute
         * @function
         *  Add element to DOM
         *  @param name {string} Element name
         */
        getAttribute:function(name)
        {
            return this.self.e.getAttribute(name);
        },
        /**
         * Removes an attribute 
         * @namespace dd.fn.removeAttribute
         * @function
         *  Add element to DOM
         *  @param name {string} Attribute name
         */
        removeAttribute:function(name)
        {
            this.self.e.removeAttribute(name);
        },
        /**
         * Set focus to an element
         * @function
         *  Sets focus
         */
        focus:function()
        {
            this.self.e.focus();
        },
        /**
         * Set focus to an element
         * @function
         *  Sets focus
         */
        select:function()
        {
            this.self.e.select();
        },
        text:function(v)
        {
            if(v)
            {
                var e = this.self.e;
                while(e.childNodes[0])
                {
                    e.removeChild(e.childNodes[0]);
                }
                e.appendChild(document.createTextNode(v));
                return v;
            }
            else
            {
                var e = this.self.e;
                return e.childNodes.length > 0
                        ? e.childNodes[0].nodeValue
                        : "";
            }
        },
        /**
         * Event
         */
        /**
         * Apply events to objects
         * @namespace dd.fn.event
         * @function
         *  @param events {object} Events
         * @function
         *  @param events {object} Events
         *  @param scope {object} Pass into scope
         */
        event:function(o, s)
        {
            var self = this.self;
            self._s = s = s || {};
            for(var i in o)
            {
                var t = self.event;
                if(!(i in t))
                {
                    t[i] = [];
                }
                t[i].push(o[i]);
                if(self.e !== null)
                {
                    self.e.addEventListener(i, (function(s, i, f)
                    {
                        return function(e)
                        {
                            var v = dd._e[i].call(this, e);
                            if(v)
                            {
                                dd.combine(v, s);
                                v.self = "attributes" in this ? {e:this} : this;
                                var r = f.call(v);
                                r = dd.is(r) ? !r : v.capture;
                                if(r)
                                {
                                    e.cancelBubble = true;
                                    if(e.stopPropagation)
                                    {
                                        e.stopPropagation();
                                    }
                                    if(e.preventDefault)
                                    {
                                        e.preventDefault();
                                    }
                                    else
                                    {
                                        e.returnValue = false;
                                    }
                                }
                            }
                        }
                    })(s, i, o[i]), true);
                }
            }
            return this;
        }
    },
    /**
     * Attaches JavaScript File
     * @namespace dd.fn.addJS
     * @function
     *  Attaches JavaScript File 
     *  @param file {string} File
     *  @returns element
     */
    addJS:function(file)
    {
        var e = dd(dd.head).addElement("script", {
            "type":"text/javascript",
            "src":file
        });
        return this;
    },
    /**
     * Removes JavaScript file
     * @namespace dd.fn.removeJS
     * @function
     *  Removes JavaScript file
     *  @param file {string} Element name
     *  @returns dd
     */
    removeJS:function(file)
    {
        dd(dd.head).each(function(){
            if(this.nodeName == "script")
            {
                if(this.src == file)
                {
                    dd.head.removeChild(this.self);
                }
            }
        });
        return this;
    },
    /**
     * Attach CSS stylesheet 
     * @namespace dd.fn.addCSS
     * @function
     *  Attach CSS stylesheet with screen media type
     *  @param file {string} File
     *  @returns dd
     * @function
     *  Attach CSS stylesheet with media type
     *  @param file {string} File
     *  @param media {string} Media
     *  @returns dd
     */
    addCSS:function(file, media)
    {
        media = media || "screen";
        var e = dd(dd.head).addElement("link", {
            "type":"text/css",
            "screen":media,
            "rel":"stylesheet",
            "href":file
        });
        return this;
    },
    /**
     * Remove CSS stylesheet 
     * @namespace dd.fn.removeCSS
     * @function
     *  Remove CSS stylesheet
     *  @param file {string} File
     *  @returns dd
     */
    removeCSS:function(file)
    {
        dd(dd.head).each(function(){
            if(this.nodeName == "link")
            {
                if(this.href == file)
                {
                    dd.head.removeChild(this.self);
                }
            }
        });
        return this;
    },
    /**
     * Trim whitespace
     * @namespace dd.trim
     * @function
     *  @param str {string} String to trim
     */
    trim:function(v)
    {
        return v.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
    },
    /**
     * @namespace dd.combine
     * @function
     *  Combine a second object into the first object
     *  @param object1 {object} The object to be extended
     *  @param object2 {object} The object to be extended into the first
     *  @returns new result of placing object1 into object2.
     *  "Combining Two Objects"[javascript]@@
     *  var obj1 = {foo:"bar"};
     *  var obj2 = {hello:"world"};
     *  {foo:"bar", hello:"world"} == dd.combine(obj1, obj2);
     *  @@
     * @function
     *  Overload allowing ignoring of properties
     */
    combine:function(o1, o2, ig)
    {
        if(!dd.is(o2))
        {
            alert("Error: dd.combine");
            return false;
        }
        ig = dd.is(ig) ? ig : {};
        if("__lookupGetter__" in o2)
        {
            for(var i in o2)
            {
                if(!(i in ig))
                {
                    var g = o2.__lookupGetter__(i),
                        s = o2.__lookupSetter__(i);
                    if(g || s)
                    {
                        if(g)
                        {
                            o1.__defineGetter__(i, g);
                        }
                        if(s)
                        {
                            o1.__defineSetter__(i, s);
                        }
                    }
                    else
                    {
                        o1[i] = o2[i];
                    }
                }
            }
        }
        else
        {
            for(var i in o2)
            {
                if(!(i in ig))
                {
                    var d = Object.getOwnPropertyDescriptor(o2, i);
                    Object.defineProperty(o1, i, d);
                }
            }
        }
        return o1;
    },
    _load:function()
    {
        dd.body = document.getElementsByTagName("body")[0];
        for(var i in dd.__load)
        {
            dd.__load[i].call(dd);
        }
    },
    _ns:{
        "svg":"http://www.w3.org/2000/svg"
    },
    _e:{
        load:function(e){return {capture:false};},
        resize:function(e)
        {
            var w = 0, h = 0;
            if(window.innerWidth)
            {
                w = window.innerWidth;
                h = window.innerHeight;
            }
            else
            {
                if(document.documentElement.clientWidth != 0)
                {
                    w = document.documentElement.clientWidth;
                    h = document.documentElement.clientHeight;
                }
                else
                {
                    w = document.body.clientWidth;
                    h = document.body.clientHeight;
                }
            }
            return {
                capture:false,
                screen:{
                    width:w,
                    height:h
                }
            };
        },
        mouseover:function(e)
        {
            if(e.which){var lb = (e.which == 1);}
            else if(e.button){var lb = (e.button == 0);}
            return {
                capture:false,
                mouse:{
                    left:lb
                    }
                };
        },
        mouseout:function(e)
        {
            return {
                capture:false,
                mouse:{
                    x:e.clientX,
                    y:e.clientY
                    }
                };
        },
        mousemove:function(e)
        {
            return {
                capture:false
                };
        },
        mousedown:function(e)
        {
            if (e.which) lb = (e.which == 1);
            else if (e.button) lb = (e.button == 1);
            return {
                capture:false,
                mouse:{left:lb}
                };
        },
        mouseup:function(e)
        {
            if (e.which) lb = (e.which == 1);
            else if (e.button) lb = (e.button == 1);
            return {
                capture:false,
                mouse:{left:lb}
                };
        },
        keypress:function(e)
        {
            var c = 0;
            if (e.keyCode) c = e.keyCode;
            else if (e.which) c = e.which;
            return {
                capture:false,
                key:{
                    code:c,
                    tab:c == 9,
                    enter:c == 13
                }
            };
        },
        keydown:function(e)
        {
            var c = 0;
            if (e.keyCode) c = e.keyCode;
            else if (e.which) c = e.which;
            return {
                capture:false,
                key:{
                    code:c,
                    tab:c == 9,
                    enter:c == 13
                }
            };
        },
        keyup:function(e)
        {
            var c = 0;
            if (e.keyCode) c = e.keyCode;
            else if (e.which) c = e.which;
            return {
                capture:false,
                key:{
                    code:c,
                    tab:c == 9,
                    enter:c == 13
                }
            };
        },
        focus:function(e)
        {
            return {capture:false};
        },
        blur:function(e)
        {
            return {capture:false};
        },
        click:function(e)
        {
            return {capture:true};
        }
    }
});
dd.addJS("http://kirupa.templarian.com/js/kirupa.js");
dd.addCSS("http://kirupa.templarian.com/js/kirupa.css");